#include <QtGui/QTreeWidget>
#include <QtGui/QVBoxLayout>
#include "3rdparty/glextensions.h"
#include "QyGLSettings.h"

/**************************************************************************************************/
static int rowCount = 0;
/**************************************************************************************************/

class QyGLOption {
public:
	explicit QyGLOption( QyGL::ViewSettings & viewSettings ) : p_viewSettings(viewSettings) {}
	virtual ~QyGLOption() {}

	virtual QString displayName() const = 0;
	virtual QStringList values() const { return QStringList(); }
	virtual QString value() const = 0;
	virtual bool isValidValue( const QString & str ) const { return values().contains(str); }

	virtual void setValue( const QString & str ) = 0;

protected:
	QyGL::ViewSettings & p_viewSettings;

};

/**************************************************************************************************/

class QyDelegateEditor : public QComboBox {
	Q_OBJECT
public:
	QyDelegateEditor( QyGLOption * option ) : p_option(option) {

		updateItems();

		connect( this, SIGNAL( activated(const QString&) ), SLOT( thisActivated(const QString&) ) );

	}
	virtual ~QyDelegateEditor() {}

	void updateItems() {

		if (!p_option)
			return;

		clear();
		addItems( p_option->values() );
		updateValue();

	}

	void updateValue() {

		if (!p_option)
			return;

		setCurrentIndex( findText( p_option->value() ) );

	}

	QTreeWidgetItem * item;

private slots:
	void thisActivated( const QString & str ) {

		if (!p_option)
			return;

		p_option->setValue(str);

	}

private:
	QyGLOption * p_option;

};

/**************************************************************************************************/

template < typename Type >
inline QTreeWidgetItem * mkitem( Type * parent, const QString & name,
	const QString & value = QString(), QyDelegateEditor * delegate = 0 )
{

	QTreeWidgetItem * item = new QTreeWidgetItem( parent, QStringList() << name << value );

	if (delegate) {

		delegate->item = item;
		item->treeWidget()->setItemWidget( item, 1, delegate );
		item->setFlags( Qt::ItemIsSelectable|Qt::ItemIsEditable|Qt::ItemIsEnabled );

	}

	item->setSizeHint( 1, QSize( 20, 20 ) );
	rowCount ++;

	return item;
}

/**************************************************************************************************/

class QyGLResolutionOption : public QyGLOption {
public:
	explicit QyGLResolutionOption( QyGL::ViewSettings & viewSettings )
		: QyGLOption(viewSettings)
	{

		addMode( QSize( 640, 480 ) );
		addMode( QSize( 800, 600 ) );
		addMode( QSize( 1024, 768 ) );
		addMode( QSize( 1280, 1024 ) );

	}

	QString displayName() const { return QyGL::SettingsDialog::tr("Resolution"); }
	QStringList values() const {

		return p_modes.keys();
	}
	QString value() const {

		QString value = QString("%1x%2")
			.arg( p_viewSettings.resolution.width() )
			.arg( p_viewSettings.resolution.height() );

		return isValidValue(value) ? value : values().first();
	}

	void setValue( const QString & str ) {

		if ( isValidValue(str) )
			p_viewSettings.resolution = strToSize(str);

	}

private:
	inline void addMode( const QSize & mode ) {

		p_modes[ QString("%1x%2").arg( mode.width() ).arg( mode.height() ) ] = mode;

	}
	inline QSize strToSize( const QString & str ) {

		return QSize( str.section( "x", 0, 0 ).toInt(), str.section( "x", 1, 1 ).toInt() );
	}
	QHash<QString,QSize> p_modes;

};

/**************************************************************************************************/

class QyGlInfo {
	struct LimitRec {
		int type,
			id;
		QString name;

		LimitRec( int a, int b, const QString & str ) : type(a), id(b), name(str) {}

	};

public:
    QString vendor() const { return QString( reinterpret_cast<const char*>( glGetString(GL_VENDOR) ) ); }
    QString render() const { return QString( reinterpret_cast<const char*>( glGetString(GL_RENDERER) ) ); }
    QString version() const { return QString( reinterpret_cast<const char*>( glGetString(GL_VERSION) ) ); }
    QStringList extensions() const { return QString( reinterpret_cast<const char*>( glGetString(GL_EXTENSIONS) ) ).split(" "); }

	// ADDREC(GL_MAX_LIST_NESTING);
	// ADDREC(GL_MAX_ATTRIB_STACK_DEPTH);
	// ADDREC(GL_MAX_MODELVIEW_STACK_DEPTH);
	// ADDREC(GL_MAX_NAME_STACK_DEPTH);
	// ADDREC(GL_MAX_PROJECTION_STACK_DEPTH);
	// ADDREC(GL_MAX_TEXTURE_STACK_DEPTH);
	// ADDREC(GL_MAX_EVAL_ORDER);
	// ADDREC(GL_MAX_LIGHTS);
	// ADDREC(GL_MAX_CLIP_PLANES);
	// ADDREC(GL_MAX_TEXTURE_SIZE);
	// ADDREC(GL_MAX_PIXEL_MAP_TABLE);
	// ADDREC(GL_MAX_VIEWPORT_DIMS);
	// ADDREC(GL_MAX_CLIENT_ATTRIB_STACK_DEPTH);

	int getInt( int id ) const {

		int type;

		glGetIntegerv( id, &type );

		return type;
	}

};

/**************************************************************************************************/

using namespace QyGL;

SettingsDialog::SettingsDialog( QWidget * parent )
	: QDialog(parent)
{

	QVBoxLayout * layout = new QVBoxLayout(this);
	view = new QTreeWidget(this);

	view->setHeaderLabels( QStringList() << "Name" << "Value" );
	layout->addWidget(view);
	setViewSettings(p_viewSettings);

}

SettingsDialog::~SettingsDialog() {
}

void SettingsDialog::setViewSettings( const ViewSettings & viewSettings ) {

	QList<QyGLOption*> options;

	p_viewSettings = viewSettings;
	options.append( new QyGLResolutionOption(p_viewSettings) );

	QyGlInfo info;

	mkitem( view, "Vendor", info.vendor() );
	mkitem( view, "Render", info.render() );
	mkitem( view, "Version", info.version() );

	QGLExtensionFunctions & exts = getGLExtensionFunctions();

	QTreeWidgetItem * glslItem = mkitem( view, "GLSL", exts.glslSupported() ? "supported" : "not supported" );

	mkitem( glslItem, "CreateShaderObjectARB", exts.CreateShaderObjectARB ? "supported" : "not supported" );
	mkitem( glslItem, "CreateShaderObjectARB", exts.CreateShaderObjectARB ? "supported" : "not supported" );
	mkitem( glslItem, "ShaderSourceARB", exts.ShaderSourceARB ? "supported" : "not supported" );
	mkitem( glslItem, "CompileShaderARB", exts.CompileShaderARB ? "supported" : "not supported" );
	mkitem( glslItem, "GetObjectParameterivARB", exts.GetObjectParameterivARB ? "supported" : "not supported" );
	mkitem( glslItem, "DeleteObjectARB", exts.DeleteObjectARB ? "supported" : "not supported" );
	mkitem( glslItem, "GetInfoLogARB", exts.GetInfoLogARB ? "supported" : "not supported" );
	mkitem( glslItem, "CreateProgramObjectARB", exts.CreateProgramObjectARB ? "supported" : "not supported" );
	mkitem( glslItem, "AttachObjectARB", exts.AttachObjectARB ? "supported" : "not supported" );
	mkitem( glslItem, "DetachObjectARB", exts.DetachObjectARB ? "supported" : "not supported" );
	mkitem( glslItem, "LinkProgramARB", exts.LinkProgramARB ? "supported" : "not supported" );
	mkitem( glslItem, "UseProgramObjectARB", exts.UseProgramObjectARB ? "supported" : "not supported" );
	mkitem( glslItem, "GetUniformLocationARB", exts.GetUniformLocationARB ? "supported" : "not supported" );
	mkitem( glslItem, "Uniform1iARB", exts.Uniform1iARB ? "supported" : "not supported" );
	mkitem( glslItem, "Uniform1fARB", exts.Uniform1fARB ? "supported" : "not supported" );
	mkitem( glslItem, "Uniform4fARB", exts.Uniform4fARB ? "supported" : "not supported" );
	mkitem( glslItem, "UniformMatrix4fvARB", exts.UniformMatrix4fvARB ? "supported" : "not supported" );

	QTreeWidgetItem * fboItem = mkitem( view, "Frame buffer objects", exts.fboSupported() ? "supported" : "not supported" );

	mkitem( fboItem, "GenFramebuffersEXT", exts.GenFramebuffersEXT ? "supported" : "not supported" );
	mkitem( fboItem, "GenRenderbuffersEXT", exts.GenRenderbuffersEXT ? "supported" : "not supported" );
	mkitem( fboItem, "BindRenderbufferEXT", exts.BindRenderbufferEXT ? "supported" : "not supported" );
	mkitem( fboItem, "RenderbufferStorageEXT", exts.RenderbufferStorageEXT ? "supported" : "not supported" );
	mkitem( fboItem, "DeleteFramebuffersEXT", exts.DeleteFramebuffersEXT ? "supported" : "not supported" );
	mkitem( fboItem, "DeleteRenderbuffersEXT", exts.DeleteRenderbuffersEXT ? "supported" : "not supported" );
	mkitem( fboItem, "BindFramebufferEXT", exts.BindFramebufferEXT ? "supported" : "not supported" );
	mkitem( fboItem, "FramebufferTexture2DEXT", exts.FramebufferTexture2DEXT ? "supported" : "not supported" );
	mkitem( fboItem, "FramebufferRenderbufferEXT", exts.FramebufferRenderbufferEXT ? "supported" : "not supported" );
	mkitem( fboItem, "CheckFramebufferStatusEXT", exts.CheckFramebufferStatusEXT ? "supported" : "not supported" );

	QTreeWidgetItem * gl15Item = mkitem( view, "GL15", exts.openGL15Supported() ? "supported" : "not supported" );

	mkitem( gl15Item, "ActiveTexture", exts.ActiveTexture ? "supported" : "not supported" );
	mkitem( gl15Item, "TexImage3D", exts.TexImage3D ? "supported" : "not supported" );
	mkitem( gl15Item, "GenBuffers", exts.GenBuffers ? "supported" : "not supported" );
	mkitem( gl15Item, "BindBuffer", exts.BindBuffer ? "supported" : "not supported" );
	mkitem( gl15Item, "BufferData", exts.BufferData ? "supported" : "not supported" );
	mkitem( gl15Item, "DeleteBuffers", exts.DeleteBuffers ? "supported" : "not supported" );
	mkitem( gl15Item, "MapBuffer", exts.MapBuffer ? "supported" : "not supported" );
	mkitem( gl15Item, "UnmapBuffer", exts.UnmapBuffer ? "supported" : "not supported" );

	QTreeWidgetItem * extensionsItem = mkitem( view, "Extensions" );

	foreach ( QString ext, info.extensions() )
		mkitem( extensionsItem, ext );

	QTreeWidgetItem * settingsItem = mkitem( view, "Settings" );

	foreach ( QyGLOption * option, options ) {

		mkitem( settingsItem, option->displayName(), option->value(), new QyDelegateEditor(option) );

	}

}

#include <QyGLSettings.moc>
